package edu.zjut.hjg.saas.web.controller.tenant;

import static edu.zjut.hjg.saas.web.support.SaaSConstants.DEFAULT_CITY_CODE;
import static edu.zjut.hjg.saas.web.support.SaaSConstants.SESSION_NAME_TENANT;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import edu.zjut.hjg.saas.biz.meta.KindergartenMeta;
import edu.zjut.hjg.saas.biz.model.City;
import edu.zjut.hjg.saas.biz.model.Kindergarten;
import edu.zjut.hjg.saas.biz.model.PriceType;
import edu.zjut.hjg.saas.biz.model.Subscribe;
import edu.zjut.hjg.saas.biz.model.Tenant;
import edu.zjut.hjg.saas.biz.service.KindergartenService;
import edu.zjut.hjg.saas.biz.service.LocationService;
import edu.zjut.hjg.saas.biz.service.PriceTypeService;
import edu.zjut.hjg.saas.biz.service.SubscribeService;
import edu.zjut.hjg.saas.biz.service.exception.ServiceException;
import edu.zjut.hjg.saas.biz.support.AppStatus;
import edu.zjut.hjg.saas.biz.util.PriceTypeUtil;
import edu.zjut.hjg.saas.common.annotation.CookieSessionIn;
import edu.zjut.hjg.saas.web.model.TenantSession;
import edu.zjut.hjg.saas.web.model.form.CreateAppForm;
import edu.zjut.hjg.saas.web.model.form.UpdateAppForm;

/**
 * 幼儿园网站管理控制器
 * 
 * @author hjg
 */
@Controller
@RequestMapping("/tenant/app")
public class AppController {

    private static final Log    log = LogFactory.getLog(AppController.class);

    @Value("${saas.web.app.server.domain}")
    private String              appDomain;

    @Value("${saas.web.app.server.port}")
    private int                 appServerPort;

    @Autowired
    private KindergartenService kindergartenService;

    @Autowired
    private LocationService     locationService;

    @Autowired
    private SubscribeService    subscribeService;

    @Autowired
    private PriceTypeService    priceTypeService;

    @CookieSessionIn(value = SESSION_NAME_TENANT, param = "session")
    @ModelAttribute("app")
    public Kindergarten prepareApp(TenantSession session) {
        // 数据准备
        return kindergartenService.findByTenantId(session.getId());
    }

    @RequestMapping("/index.htm")
    public void index(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app != null) {
            String appServerUrl = "http://" + app.getSiteDomain();
            if (appServerPort != 80) {
                appServerUrl = appServerUrl + ":" + appServerPort;
            }
            model.put("appServerUrl", appServerUrl);
        }
    }

    @RequestMapping("/create.htm")
    @CookieSessionIn(value = SESSION_NAME_TENANT, param = "session")
    public String create(ModelMap model, TenantSession session) {
        if (model.get("app") != null) {
            // 已经有幼儿园网站
            return "redirect:/tenant/app/index.htm";
        }
        CreateAppForm appForm = new CreateAppForm();
        // 默认值
        setDefaultProperties(session, appForm);
        model.addAttribute("appForm", appForm);
        prepareModel(model, DEFAULT_CITY_CODE);
        return "tenant/app/create";
    }

    @RequestMapping(value = "/doCreate.htm", method = RequestMethod.POST)
    @CookieSessionIn(value = SESSION_NAME_TENANT, param = "session")
    public String doCreate(@Valid @ModelAttribute("appForm") CreateAppForm appForm,
                           BindingResult result, TenantSession session, ModelMap model) {
        if (model.get("app") != null) {
            // 已经有幼儿园网站
            return "redirect:/tenant/app/index.htm";
        }
        if (result.hasErrors()) {
            prepareModel(model, appForm.getCityCode());
            return "tenant/app/create";
        }
        Kindergarten app = new Kindergarten();
        setKindergarten(app, appForm, session);
        try {
            kindergartenService.create(app);
        } catch (ServiceException e) {
            log.error(e.getMessage() + ", " + e.getErrorMessage(), e);
            result.reject("error.createApp.form", e.getErrorMessage());
            prepareModel(model, app.getCity().getCode());
            return "tenant/app/create";
        }
        return "redirect:/tenant/app/index.htm";
    }

    @RequestMapping("/update.htm")
    public String update(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null) {
            // 还没有幼儿园网站
            return "redirect:/tenant/app/index.htm";
        }
        CreateAppForm appForm = new CreateAppForm();
        // 默认值
        appForm.setCityCode(app.getCity().getCode());
        appForm.setDomainPrefix(getDomainPrefix(app.getSiteDomain()));
        appForm.setName(app.getName());
        appForm.setIntroduction(app.getIntroduction());
        model.addAttribute("appForm", appForm);
        prepareModel(model, appForm.getCityCode());
        return "tenant/app/update";
    }

    @RequestMapping(value = "/doUpdate.htm", method = RequestMethod.POST)
    @CookieSessionIn(value = SESSION_NAME_TENANT, param = "session")
    public String doUpdate(@Valid @ModelAttribute("appForm") UpdateAppForm appForm,
                           BindingResult result, TenantSession session, ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null) {
            // 还没有幼儿园网站
            return "redirect:/tenant/app/index.htm";
        }
        if (result.hasErrors()) {
            prepareModel(model, appForm.getCityCode());
            return "tenant/app/update";
        }
        setKindergarten(app, appForm, session);
        // 如果被驳回，则修改为等待审核
        if (app.isRejected()) {
            app.setStatus(AppStatus.UNAUDITED);
        }
        try {
            kindergartenService.update(app);
        } catch (ServiceException e) {
            log.error(e.getMessage() + ", " + e.getErrorMessage(), e);
            result.reject("error.updateApp.form", e.getErrorMessage());
            prepareModel(model, app.getCity().getCode());
            return "tenant/app/update";
        }
        return "redirect:/tenant/app/index.htm";
    }

    @RequestMapping("/subscribe.htm")
    public String subscribe(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null || !app.isAudited()) {
            return "redirect:/tenant/app/index.htm";
        }
        model.addAttribute("priceTypes", priceTypeService.listAll());
        return "tenant/app/subscribe";
    }

    @RequestMapping(value = "/doSubscribe.htm", method = RequestMethod.POST)
    public String doSubscribe(@RequestParam("priceTypeId") int priceTypeId,
                              @RequestParam("leaseTerm") int leaseTerm, ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null || !app.isAudited()) {
            return "redirect:/tenant/app/index.htm";
        }
        subscribeService.subscribeApp(priceTypeId, app.getId(), leaseTerm);
        return "redirect:/tenant/app/index.htm";
    }

    @RequestMapping("/detail.htm")
    public String detail(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null || !app.isEnabled()) {
            return "redirect:/tenant/app/index.htm";
        }
        model.addAttribute("subscribe", subscribeService.findByKindergartenId(app.getId()));
        return "tenant/app/detail";
    }

    @RequestMapping("/config.htm")
    public String config(ModelMap model) {
        if (model.get("app") == null) {
            // 没有幼儿园网站
            return "redirect:/tenant/app/index.htm";
        }
        model.put("themes", kindergartenService.getThemes());
        return "tenant/app/config";
    }

    @RequestMapping(value = "/doConfig.htm", method = RequestMethod.POST)
    public String doConfig(ModelMap model, @RequestParam("theme") String theme) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null) {
            // 没有幼儿园网站
            return "redirect:/tenant/app/index.htm";
        }
        KindergartenMeta meta = app.getMeta();
        meta.setTheme(theme);
        kindergartenService.updateConfig(meta);
        return "redirect:/tenant/app/config.htm";
    }

    @RequestMapping("/disable.htm")
    public String disable(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null || !app.isEnabled()) {
            return "redirect:/tenant/app/index.htm";
        }
        Subscribe subscribe = subscribeService.findByKindergartenId(app.getId());
        model.put("subscribe", subscribe);
        if (!subscribe.isFreeTrial()) {
            Date startDate = app.getStartDate();
            PriceType priceType = subscribe.getPriceType();
            int lastDays = PriceTypeUtil.getLastDays(startDate, priceType);
            model.put("lastDays", lastDays);
            model.put("lastSpend", PriceTypeUtil.getSpend(lastDays, priceType));
        }
        return "tenant/app/disable";
    }

    @RequestMapping("/doDisable.htm")
    public String doDisable(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app != null && app.isEnabled()) {
            kindergartenService.disable(app);
        }
        return "redirect:/tenant/app/index.htm";
    }

    @RequestMapping("/enable.htm")
    public String enable(ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null || !app.isDisabled()) {
            return "redirect:/tenant/app/index.htm";
        }
        model.addAttribute("priceTypes", priceTypeService.listAll());
        return "tenant/app/enable";
    }

    @RequestMapping(value = "/doEnable.htm", method = RequestMethod.POST)
    public String doEnable(@RequestParam("priceTypeId") int priceTypeId,
                           @RequestParam("leaseTerm") int leaseTerm, ModelMap model) {
        Kindergarten app = (Kindergarten) model.get("app");
        if (app == null || !app.isDisabled()) {
            return "redirect:/tenant/app/index.htm";
        }
        try {
            kindergartenService.enable(app, priceTypeId, leaseTerm);
        } catch (ServiceException e) {
            log.info(e.getErrorMessage(), e);
            model.put("message", e.getErrorMessage());
            model.addAttribute("priceTypes", priceTypeService.listAll());
            return "tenant/app/enable";
        }
        return "redirect:/tenant/app/index.htm";
    }

    private void prepareModel(ModelMap model, String cityCode) {
        City city = locationService.findCityByCityCode(cityCode);
        model.addAttribute("provinces", locationService.listAllProvinces());
        model.addAttribute("cities", getCityOptions(locationService.listCitesByProvinceCode(city
                .getProvince().getCode())));
        model.addAttribute("city", city);
        model.addAttribute("appDomain", appDomain);
    }

    private void setDefaultProperties(TenantSession session, CreateAppForm appForm) {
        appForm.setCityCode(DEFAULT_CITY_CODE);
        appForm.setDomainPrefix(session.getLoginId().replaceAll("_", "-").toLowerCase());
        appForm.setName(session.getName());
    }

    private Map<String, String> getCityOptions(List<City> cities) {
        Map<String, String> cityOptions = new HashMap<String, String>();
        for (City city : cities) {
            cityOptions.put(city.getCode(), city.getName());
        }
        return cityOptions;
    }

    private void setKindergarten(Kindergarten kindergarten, CreateAppForm appForm,
                                 TenantSession session) {
        City city = new City();
        city.setCode(appForm.getCityCode());
        Tenant tenant = new Tenant();
        tenant.setId(session.getId());
        kindergarten.setCity(city);
        kindergarten.setIntroduction(appForm.getIntroduction());
        kindergarten.setName(appForm.getName());
        kindergarten.setTenant(tenant);
        kindergarten.setSiteDomain(appForm.getDomainPrefix().toLowerCase() + appDomain);
    }

    private String getDomainPrefix(String siteDomain) {
        return siteDomain.substring(0, siteDomain.indexOf('.'));
    }
}
